package engine.planets;

import engine.math.MT19937;
import engine.stars.RegularStar;
import engine.utils.DecToRomanConverter;

public class PlanetGenerator {
	/* Счетчик созданных для данного сектора газовых гигантов. */
	private static int gasGiantCounter = 0;

	/* Создаю локальные константы, чтоб массив красиво и читабельно выглядел */
	private static final int COLD = Planet.CLIMATE_ICE;
	private static final int VOLCANIC = Planet.CLIMATE_VOLCANIC;
	private static final int WARM = Planet.CLIMATE_COMFORT;

	/*
	 * Двумерный массив, который хранит зависимость климата от спектрального
	 * класса материнской звезды и орбиты
	 */
	private static final int[][] SPECT_CLASS_AND_ORBIT_TO_CLIMATE = {
		{WARM, COLD, COLD, COLD, COLD, COLD},
		{WARM, WARM, COLD, COLD, COLD, COLD},
		{VOLCANIC, WARM, WARM, COLD, COLD, COLD},
		{VOLCANIC, VOLCANIC, WARM, WARM, COLD, COLD},
		{VOLCANIC, VOLCANIC, VOLCANIC, VOLCANIC, WARM, COLD},
		{VOLCANIC, VOLCANIC, VOLCANIC, VOLCANIC, VOLCANIC, WARM},
		{VOLCANIC, VOLCANIC, VOLCANIC, VOLCANIC, VOLCANIC, VOLCANIC}};

	/**
	 * Генерирует все планеты для звезды.
	 *
	 * @param star материнская звезда
	 * @return сгенерированные планеты
	 */
	public static Planet[] generatePlanets(RegularStar star) {
		int plntQuant = star.getPlanetsQuantity();
		Planet[] planets = new Planet[plntQuant];

		for (int i = 0; i < plntQuant; i++) {
			planets[i] = createNewPlanet(i + 1, plntQuant, star.getSpectralClass(), star.getName());
		}

		return planets;
	}

	/**
	 * Генерирует планету по заданным характеристикам звезды
	 *
	 * @param orbit
	 * @param numberOfPlanets
	 * @param spectralClassOfMotherStar
	 * @param nameOfMotherStar
	 * @return получаем планету по заданным законам
	 */
	private static Planet createNewPlanet(int orbit, int numberOfPlanets,
		int spectralClassOfMotherStar, String nameOfMotherStar) {
		MT19937 mt = new MT19937();
		double randNum = mt.nextDouble();
		Planet newPlanet;
		if ((randNum <= 0.5) && gasGiantIsPermitted(orbit, numberOfPlanets)) {
			newPlanet = new GasGiant();
			gasGiantCounter++;
		} else {
			newPlanet = new EarthTypePlanet(orbit, spectralClassOfMotherStar);
		}
		newPlanet.setOrbit(orbit);
		newPlanet.setName(nameOfMotherStar + " " + DecToRomanConverter.DecToRoman(orbit));
		return newPlanet;
	}

	/**
	 * @return получаем гравитацию планеты по нормальному распределению
	 */
	protected static double generateGravity() {
		int gravity;
		MT19937 mt = new MT19937();
		gravity = mt.nextInt(8);
		return gravity;
	}

	/**
	 * @return получаем ресурсное богатство планеты по нормальному распределению
	 */
	protected static int generateResourceWealth() {
		int resourceWealth;
		MT19937 mt = new MT19937();
		double randNum = mt.nextDouble();
		if (randNum <= 0.2) {
			resourceWealth = Planet.RESOURCE_WEALTH_VERY_POOR;
		} else if (randNum <= 0.4) {
			resourceWealth = Planet.RESOURCE_WEALTH_POOR;
		} else if (randNum <= 0.6) {
			resourceWealth = Planet.RESOURCE_WEALTH_EARTH_LIKE;
		} else if (randNum <= 0.8) {
			resourceWealth = Planet.RESOURCE_WEALTH_RICH;
		} else {
			resourceWealth = Planet.RESOURCE_WEALTH_VERY_RICH;
		}
		return resourceWealth;
	}

	/**
	 * @return получаем уровень радиактивности планеты по нормальному
	 *         распределению
	 */
	protected static int generateRadioactivity() {
		int radioactivity;
		MT19937 mt = new MT19937();
		double randNum = mt.nextDouble();
		if (randNum <= 0.335) {
			radioactivity = Planet.RADIOACTIVITY_NORMAL;
		} else if (randNum <= 0.665) {
			radioactivity = Planet.RADIOACTIVITY_HIGH;
		} else {
			radioactivity = Planet.RADIOACTIVITY_DEADLY;
		}
		return radioactivity;
	}

	/**
	 * @param planetClimate вводим климат планеты
	 * @param atmosphere вводим атмосферу планеты
	 * @return получаем соотношение суши и воды на планете
	 */
	protected static double generateRatioOfLandAndWater(int planetClimate, int atmosphere) {
		double ratio;
		MT19937 mt = new MT19937();
		double randNum = mt.nextDouble();
		if ((planetClimate == Planet.CLIMATE_COMFORT) && (atmosphere != Planet.ATMOSPHERE_NONE)) {
			if (randNum <= 0.2) {
				ratio = Planet.RATIO_OF_LAND_WATERWORLD;
			} else if (randNum <= 0.4) {
				ratio = Planet.RATIO_OF_LAND_ARCHIPELAGO;
			} else if (randNum <= 0.6) {
				ratio = Planet.RATIO_OF_LAND_MEDITERRANEAN;
			} else if (randNum <= 0.8) {
				ratio = Planet.RATIO_OF_LAND_EARTH_LIKE;
			} else {
				ratio = Planet.RATIO_OF_LAND_DESERT;
			}
		} else {
			ratio = Planet.RATIO_OF_LAND_DESERT;
		}
		return ratio;
	}

	/**
	 * @param planetClimate
	 * @return получаем атмосферу планеты
	 */
	protected static int generateAtmosphere(int planetClimate) {
		int atmosphere;
		MT19937 mt = new MT19937();
		double randNum = mt.nextDouble();
		if (planetClimate != Planet.CLIMATE_VOLCANIC) {
			if (randNum <= 0.335) {
				atmosphere = Planet.ATMOSPHERE_NONE;
			} else if (randNum <= 0.665) {
				atmosphere = Planet.ATMOSPHERE_EARTH_LIKE;
			} else {
				atmosphere = Planet.ATMOSPHERE_POISON;
			}
		} else {
			if (randNum <= 0.9) {
				atmosphere = Planet.ATMOSPHERE_NONE;
			} else {
				atmosphere = Planet.ATMOSPHERE_POISON;
			}
		}
		return atmosphere;
	}

	/**
	 * @return получаем размер планеты по нормальному распределению
	 */
	protected static int generateSize() {
		int size;
		MT19937 mt = new MT19937();
		double randNum = mt.nextDouble();
		if (randNum <= 0.25) {
			size = Planet.SIZE_DWARF;
		} else if (randNum <= 0.5) {
			size = Planet.SIZE_EARTH_LIKE;
		} else if (randNum <= 0.75) {
			size = Planet.SIZE_BIG;
		} else {
			size = Planet.SIZE_GIANT;
		}
		return size;
	}

	/**
	 * @param currentOrbit вводим орбиту текущей планеты
	 * @param spectralClassOfMotherStar вводим спектральный класс материнской
	 *        звезды
	 * @return получаем климат
	 */
	/**
	 * @param currentOrbit
	 * @param spectralClassOfMotherStar
	 * @return
	 * @throws IllegalArgumentException
	 */
	protected static int generateClimate(int currentOrbit, int spectralClassOfMotherStar)
		throws IllegalArgumentException {
		if ((currentOrbit > 6) || (currentOrbit < 1) || (spectralClassOfMotherStar > 6)
			|| (spectralClassOfMotherStar < 0)) {
			throw new IllegalArgumentException();
		}
		return SPECT_CLASS_AND_ORBIT_TO_CLIMATE[spectralClassOfMotherStar][currentOrbit - 1];
	}

	/**
	 * @param orbit вводим орбиту текущей планеты
	 * @param numberOfPlanets вводим общее число планет в секторе
	 * @return получаем разрешение на генерацию газового гиганта
	 */
	private static boolean gasGiantIsPermitted(int orbit, int numberOfPlanets) {
		boolean gasGiantPermission = true;
		if (numberOfPlanets > 3) {
			if (((orbit != 3) && (orbit != 4)) || (gasGiantCounter == 2)) {
				gasGiantPermission = false;
			}
		} else {
			if ((orbit != numberOfPlanets) || (gasGiantCounter == 1)) {
				gasGiantPermission = false;
			}
		}
		if (orbit == numberOfPlanets) {
			gasGiantCounter = 0;
		}
		return gasGiantPermission;
	}

}
